using IQIGame.Onigao.Game;
using IQIGame.Onigao.GamePlay;
using NetProtocol.Enum;
using NetProtocol.POD;
using System;
using System.Collections.Generic;

namespace IQIGame.Onigao.Logic
{
    public partial class LevelRegion
    {
        private static Converter<BaseEntity, LevelEntityPOD> _converterEntitiesToPODs = entity => entity.GeneratePOD() as LevelEntityPOD;
        private static Converter<LevelEntity, int> _converterEntitiesToIds = entity => entity.id;

        private List<LevelEntity> _tempQueryEntities = new List<LevelEntity>();
        private List<LevelEntity> _tempAOIMoveNewEntities = new List<LevelEntity>();
        private List<LevelEntity> _tempAOIMoveRemoveEntities = new List<LevelEntity>();
        private List<LevelEntity> _tempSendEntities = new List<LevelEntity>();
        private List<LevelBuffChangeParam> _tempBuffChanges = new List<LevelBuffChangeParam>();
        private List<long> _tempBuffHostIds = new List<long>();

        /// <summary>
        /// 刷新AOI实体，同步实体数据
        /// </summary>
        /// <param name="player"></param>
        /// <param name="refreshAreaEntity">是否刷新区域实体（如第一次进入该地区时，一定会刷新，后续正常移动则不再刷新。区域实体实际不在AOI列表中，但客户端需要提前创建该地区所有区域实体，以处理特殊逻辑。）</param>
        public void RefreshPlayerAOIEntities(LevelPlayer player, bool refreshAreaEntity)
        {
            CalcAOIEntities(player, refreshAreaEntity, out var modifiedList, out var removedList);
            if (modifiedList != null || removedList != null)
            {
                Inner_SC_UpdateEntities(player, modifiedList, removedList);
            }
        }

        /// <summary>
        /// 计算AOI实体
        /// </summary>
        /// <param name="player"></param>
        /// <param name="refreshAreaEntity">是否刷新区域实体（如第一次进入该地区时，一定会刷新，后续正常移动则不再刷新。区域实体实际不在AOI列表中，但客户端需要提前创建该地区所有区域实体，以处理特殊逻辑。）</param>
        public void CalcAOIEntities(LevelPlayer player, bool refreshAreaEntity, out List<LevelEntityPOD> modifiedList, out List<int> removedList)
        {
            if (!player.isInMainPhasing)
            {
                modifiedList = null;
                removedList = null;
                return;
            }
            LevelHeroEntity heroEntity = player.entity;
            Vector3Logic position = heroEntity.position;

            //从aoi列表中删除超出了范围的实体，注意删除的范围比aoi更大，避免玩家反复横跳
            foreach (var entity in heroEntity.aoiEntities)
            {
                float sqrDistance = (heroEntity.position - entity.position).sqrMagnitude;
                if (sqrDistance >= LgLevelConst.SqrAOIRemoveRadius && !player.isTrackingEntity(entity))
                {
                    _tempQueryEntities.Add(entity);
                }
            }
            for (int i = 0; i < _tempQueryEntities.Count; i++)
            {
                LevelEntity entity = _tempQueryEntities[i];
                heroEntity.RemoveAOIEntity(entity);
                _tempAOIMoveRemoveEntities.Add(entity);
            }
            _tempQueryEntities.Clear();

            //把新进入aoi范围的实体添加进aoi列表
            float halfSize = LgLevelConst.AOIRadius;
            float searchSize = halfSize * 2;
            RectLogic searchRect = new RectLogic(position.x - halfSize, position.z - halfSize, searchSize, searchSize);
            terrain.QuadSearchEntity(_tempQueryEntities, searchRect);
            //过滤aoi范围内的所有实体
            foreach (LevelEntity entity in _tempQueryEntities)
            {
                //区域实体仅进入地区时通知添加，不进入aoi列表，也不会因为AOI变化移除
                if (entity.HasDynamicParam(EntityDynamicParamType.Area))
                {
                    continue;
                }
                float sqrDistance = (heroEntity.position - entity.position).sqrMagnitude;
                //进入了aoi范围，需添加到aoi列表中。
                if (sqrDistance < LgLevelConst.SqrAOIRadius)
                {
                    if (heroEntity.AddAOIEntity(entity))
                    {
                        //之前不在aoi列表里的为新添加的
                        _tempAOIMoveNewEntities.Add(entity);
                    }
                }
            }
            //特殊写入追踪中的任务的目标实体
            foreach (var entity in player.trackQuestTargetsExceptArea)
            {
                if (heroEntity.AddAOIEntity(entity))
                {
                    //之前不在aoi列表里的为新添加的
                    _tempAOIMoveNewEntities.Add(entity);
                }
            }
            //特殊写入追踪中的实体（地区唯一）
            if (heroEntity.AddAOIEntity(player.manualTrackingEntity))
            {
                //之前不在aoi列表里的为新添加的
                _tempAOIMoveNewEntities.Add(player.manualTrackingEntity);
            }

            //区域实体恒定属于可见实体
            //区域实体不在aoi列表中
            if (refreshAreaEntity)
            {
                foreach (LevelEntity areaEntity in _areaEntities)
                {
                    //区域实体不在aoi列表中，这里仅进入地区时通知
                    _tempAOIMoveNewEntities.Add(areaEntity);
                }
            }

            modifiedList = null;
            removedList = null;
            //发送更新aoi实体的消息
            if (_tempAOIMoveNewEntities.Count > 0 || _tempAOIMoveRemoveEntities.Count > 0)
            {
                modifiedList = EntitiesToPODs(_tempAOIMoveNewEntities);
                removedList = EntitiesToIds(_tempAOIMoveRemoveEntities);
            }

            _tempQueryEntities.Clear();
            _tempAOIMoveNewEntities.Clear();
            _tempAOIMoveRemoveEntities.Clear();
        }

        /// <summary>
        /// 清除所有aoi实体（不会发送通知）
        /// </summary>
        /// <param name="player"></param>
        /// <returns></returns>
        private List<int> ClearAllAOIEntities(LevelPlayer player)
        {
            LevelHeroEntity heroEntity = player.entity;
            if (heroEntity.aoiEntities.Count == 0)
            {
                return null;
            }
            List<int> removeEntityIds = new List<int>();
            foreach (var entity in heroEntity.aoiEntities)
            {
                removeEntityIds.Add(entity.id);
            }
            heroEntity.aoiEntities.Clear();
            //特殊处理，区域实体恒定属于AOI实体，但它不在AOI列表中，所以清空时要一起移除
            foreach (LevelEntity areaEntity in _areaEntities)
            {
                removeEntityIds.Add(areaEntity.id);
            }
            return removeEntityIds;
        }

        /// <summary>
        /// 清除所有aoi实体并发送通知更新实体显示
        /// </summary>
        /// <param name="player"></param>
        public void ClearAllAOIEntitiesAndNotify(LevelPlayer player)
        {
            var removeList = ClearAllAOIEntities(player);
            if (removeList != null)
            {
                Inner_SC_UpdateEntities(player, null, removeList, false, true);
            }
        }

        private List<LevelEntityPOD> EntitiesToPODs(List<LevelEntity> entities)
        {
            if (entities == null || entities.Count == 0)
            {
                return null;
            }
            return entities.ConvertAll(_converterEntitiesToPODs);
        }

        private List<int> EntitiesToIds(List<LevelEntity> entities)
        {
            if (entities == null || entities.Count == 0)
            {
                return null;
            }
            return entities.ConvertAll(_converterEntitiesToIds);
        }

        #region Notify 封装
        public void NotifyEnterRegion(LevelPlayer movingPlayer, List<LevelEntityPOD> modifiedList)
        {
            //通知当前玩家进入地区
            LevelRegionPOD regionPOD = GeneratePOD() as LevelRegionPOD;
            regionPOD.unsafe_entities = modifiedList;
            SLevelLogicModule.NetCore.SC_NotifyEnterRegion(movingPlayer.session, regionPOD);
            //通知该地区其他玩家有实体出生
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                if (p != movingPlayer)
                {
                    //不能用广播
                    Inner_SC_UpdateEntities(p,
                        new List<LevelEntityPOD>() { movingPlayer.GeneratePOD() as LevelEntityPOD }, null);
                }
            }
        }

        public void NotifySyncPosition(LevelPlayer player, LevelMoveReason reason, LevelEntityType entityType, BaseEntity entity, Vector3Logic position, float speedRatio, EntityMoveDirType dirType)
        {
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                //同步位置可能包含了英雄实体
                //当实体是英雄时，仅“其他玩家的英雄正常移动”或“自己的英雄移动失败”以及“非移动”时同步
                bool isSyncHero;
                switch (reason)
                {
                    case LevelMoveReason.Move:
                    case LevelMoveReason.TakeElevator:
                        isSyncHero = p != player;
                        break;
                    case LevelMoveReason.MoveFail:
                        isSyncHero = p == player;
                        LogicLog.LogWarning($"移动失败，将把英雄实体拉回位置：{p.entity.position}");
                        break;
                    default:
                        isSyncHero = true;
                        break;
                }
                //不能用广播，因为英雄策略同步会根据不同玩家不同
                if ((entityType == LevelEntityType.Hero && isSyncHero) || p.IsInterested(entity as LevelEntity))
                {
                    SLevelLogicModule.NetCore.SC_NotifySyncPosition(p.session, reason, entity.id, entityType, (float)position.x, (float)position.y, (float)position.z, speedRatio, (byte)dirType);
                }
            }
        }

        public void UpdateHeroCarrier(LevelPlayer player, LevelEntity entity, bool isRemoved)
        {
            List<ISession> sessions = ListPool<ISession>.Get();
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                if (p.IsInterested(entity))
                {
                    sessions.Add(p.session);
                }
            }
            SLevelLogicModule.NetCore.SC_UpdateHeroCarrier_Broadcast(sessions, player.entity.id, entity.id, isRemoved);
            ListPool<ISession>.Put(sessions);
        }

        #region UpdateEntities
        public void UpdateEntity(LevelPlayer player, LevelEntity entity)
        {
            List<ISession> sessions = ListPool<ISession>.Get();
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                if (p.isInMainPhasing && p.IsInterested(entity))
                {
                    sessions.Add(p.session);
                }
            }
            if (sessions.Count > 0)
            {
                SLevelLogicModule.NetCore.SC_UpdateEntities_Broadcast(sessions,
                            new List<LevelEntityPOD>() { entity.GeneratePOD() as LevelEntityPOD }, null, true);
            }
            ListPool<ISession>.Put(sessions);
        }

        public void UpdateEntities(LevelPlayer player, IReadOnlyList<LevelEntity> entities)
        {
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                //每个人的实体列表不一样，不能用广播
                if (p.GetInterestedFromList(entities, _tempSendEntities))
                {
                    Inner_SC_UpdateEntities(p,
                        _tempSendEntities.ConvertAll(_converterEntitiesToPODs), null);
                    _tempSendEntities.Clear();
                }
            }
        }

        public void UpdateRemoveEntities(LevelPlayer player, IReadOnlyList<LevelEntity> entities)
        {
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                //每个人的实体列表不一样，不能用广播
                if (p.GetInterestedFromList(entities, _tempSendEntities, true, true))
                {
                    Inner_SC_UpdateEntities(p,
                        null, _tempSendEntities.ConvertAll(_converterEntitiesToIds));
                    _tempSendEntities.Clear();
                }
            }
        }

        private void Inner_SC_UpdateEntities(LevelPlayer player, List<LevelEntityPOD> modifiedList, List<int> removedList, bool isPlayDieWhenRemove = true, bool isForce = false)
        {
            if (!isForce && !player.isInMainPhasing)
            {
                return;
            }
            SLevelLogicModule.NetCore.SC_UpdateEntities(player.session, modifiedList, removedList, isPlayDieWhenRemove);
        }
        #endregion

        public void NotifyShowSpeechBubble(LevelPlayer player, LevelEntity entity, int bubbleGroupId, List<int> validBubbleIds)
        {
            List<ISession> sessions = ListPool<ISession>.Get();
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                if (entity == null || p.IsInterested(entity)) //实体为空代表气泡在玩家头上
                {
                    sessions.Add(p.session);
                }
            }
            SLevelLogicModule.NetCore.SC_NotifyShowSpeechBubble_Broadcast(sessions, entity != null ? entity.id : 0, bubbleGroupId, validBubbleIds);
            ListPool<ISession>.Put(sessions);
        }

        /// <summary>
        /// 改变实体的隐藏状态
        /// 由于激活失活改为当做出生和死亡处理，纯粹修改可见性的代码暂时无效
        /// </summary>
        /// <param name="player"></param>
        /// <param name="entities"></param>
        /// <param name="isActive"></param>
        /// <param name="animActionId"></param>
        /// <param name="isSetRotation"></param>
        /// <param name="rotationY"></param>
        [Obsolete]
        public void UpdateEntityActivation(LevelPlayer player, IReadOnlyList<LevelEntity> entities, bool isActive, int animActionId, bool isSetRotation, int rotationY)
        {
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                //每个人的不一样，不能用广播
                if (p.GetInterestedFromList(entities, _tempSendEntities, true))
                {
                    SLevelLogicModule.NetCore.SC_UpdateEntityActivation(p.session,
                        _tempSendEntities.ConvertAll(_converterEntitiesToIds), isActive, animActionId, isSetRotation, rotationY);
                    _tempSendEntities.Clear();
                }
            }
        }

        public void NotifyActivateElevator(LevelPlayer player, LevelEntity elevator, int targetFloor, bool isRidingMode, bool isMoveState)
        {
            List<ISession> sessions = new List<ISession>();
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                if (p.IsInterested(elevator))
                {
                    sessions.Add(p.session);
                }
            }
            SLevelLogicModule.NetCore.SC_NotifyActivateElevator_Broadcast(sessions, elevator.id, targetFloor, isRidingMode, isMoveState);
        }

        /// <summary>
        /// 切屏只对指定玩家生效
        /// </summary>
        /// <param name="player"></param>
        /// <param name="levelScreenSwitchCid"></param>
        public void NotifyStartCameraMotion(LevelPlayer player, int levelScreenSwitchCid)
        {
            SLevelLogicModule.NetCore.SC_NotifyStartCameraMotion(player.session, levelScreenSwitchCid);
        }

        public void NotifyEntityObstacleChange(LevelPlayer player, IReadOnlyList<LevelEntity> entities, bool isObstacleActive)
        {
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                //每个人的不一样，不能用广播
                if (p.GetInterestedFromList(entities, _tempSendEntities))
                {
                    SLevelLogicModule.NetCore.SC_NotifyEntityObstacleChange(p.session,
                                _tempSendEntities.ConvertAll(_converterEntitiesToIds), isObstacleActive);
                    _tempSendEntities.Clear();
                }
            }
        }

        public void NotifyPlayEntityAnimAction(LevelPlayer player, List<LevelEntity> entityList, int actionId)
        {
            List<int> entityIds = new List<int>();
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                foreach (var entity in entityList)
                {
                    if (p.IsInterested(entity))
                    {
                        entityIds.Add(entity.id);
                    }
                }
                if (entityIds.Count > 0)
                {
                    SLevelLogicModule.NetCore.SC_NotifyPlayEntityAnimAction(p.session, entityIds, actionId);
                    entityIds.Clear();
                }
            }
        }

        public void NotifyPlayEntityAnimAction(LevelPlayer player, LevelEntity entity, int actionId)
        {
            List<int> entityIds = new List<int>();
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                if (p.IsInterested(entity))
                {
                    entityIds.Add(entity.id);
                }
                if (entityIds.Count > 0)
                {
                    SLevelLogicModule.NetCore.SC_NotifyPlayEntityAnimAction(p.session, entityIds, actionId);
                    entityIds.Clear();
                }
            }
        }

        public void NotifyLevelTimeShowChange(LevelPlayer player, int timeHour)
        {
            List<ISession> sessions = new List<ISession>();
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                sessions.Add(p.session);
            }
            SLevelLogicModule.NetCore.SC_NotifyLevelTimeShowChange_Broadcast(sessions, timeHour);
        }

        public void NotifyChangeSceneEffect(LevelPlayer player, LevelEntity entity, int sceneEffectId, bool isAdd)
        {
            List<ISession> sessions = new List<ISession>();
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                if (entity == null || p.IsInterested(entity))
                {
                    sessions.Add(p.session);
                }
            }
            SLevelLogicModule.NetCore.SC_NotifyChangeSceneEffect_Broadcast(sessions, entity == null ? 0 : entity.id, sceneEffectId, isAdd);
        }

        public void UpdateEntityRotationY(LevelPlayer player, BaseEntity entity, LevelEntityType entityType, int rotationY)
        {
            List<ISession> sessions = new List<ISession>();
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                if (entity is LevelHeroEntity || p.IsInterested(entity as LevelEntity))
                {
                    sessions.Add(p.session);
                }
            }
            SLevelLogicModule.NetCore.SC_UpdateEntityRotationY_Broadcast(sessions, entity.id, entityType, rotationY);
        }

        public void NotifyActiveCheckPoint(LevelPlayer player, LevelEntity entity, bool isActive)
        {
            List<ISession> sessions = new List<ISession>();

            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                if (p.IsInterested(entity))
                {
                    sessions.Add(p.session);
                }
            }
            SLevelLogicModule.NetCore.SC_NotifyActiveCheckPoint_Broadcast(sessions, entity.id, isActive);
        }

        public void NotifyBuffChange(IReadOnlyList<LevelBuffChangeParam> changes)
        {
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                for (int j = 0; j < changes.Count; j++)
                {
                    LevelBuffChangeParam buffChange = changes[j];
                    switch (buffChange.hostType)
                    {
                        case LevelBuffHostType.Player:
                            _tempBuffChanges.Add(buffChange);
                            _tempBuffHostIds.Add((buffChange.host as LevelPlayer).id);
                            break;
                        case LevelBuffHostType.AllHeroes:
                        case LevelBuffHostType.SingleHero:
                            LevelHero hero = buffChange.host as LevelHero;
                            if (hero.player == p) //只同步自己英雄
                            {
                                _tempBuffChanges.Add(buffChange);
                                _tempBuffHostIds.Add((buffChange.host as LevelHero).id);
                            }
                            break;
                        case LevelBuffHostType.Entity:
                            LevelEntity entity = buffChange.host as LevelEntity;
                            if (p.IsInterested(entity)) //只同步aoi范围内的实体
                            {
                                _tempBuffChanges.Add(buffChange);
                                _tempBuffHostIds.Add(entity.id);
                            }
                            break;
                    }
                }
                if (_tempBuffHostIds.Count > 0)
                {
                    List<LevelBuffChangePOD> changePODs = new List<LevelBuffChangePOD>();
                    for (int j = 0; j < _tempBuffChanges.Count; j++)
                    {
                        LevelBuffChangeParam buffChange = _tempBuffChanges[j];
                        LevelBuffChangePOD pod = buffChange.GeneratePODWithoutHostId();
                        pod.hostId = _tempBuffHostIds[i];
                        changePODs.Add(pod);
                    }
                    _tempBuffChanges.Clear();
                    _tempBuffHostIds.Clear();
                    SLevelLogicModule.NetCore.SC_NotifyBuffChange(p.session, changePODs);
                }
            }
        }

        public void NotifyCustomBgmChange(LevelRegion targetRegion, int bgmAudioCid)
        {
            List<ISession> sessions = new List<ISession>();
            for (int i = 0; i < targetRegion.players.Count; i++)
            {
                LevelPlayer player = players[i];
                sessions.Add(player.session);
            }
            SLevelLogicModule.NetCore.SC_NotifyCustomBgmChange_Broadcast(sessions, bgmAudioCid);
        }

        public void NotifyStartStoryDialog(LevelPlayer triggerServicePlayer, bool isGlobal, int dialogCid, int jumpCid, LevelEntity interactingEntity)
        {
            int entityId = interactingEntity == null ? 0 : interactingEntity.id;
            if (!isGlobal)
            {
                SLevelLogicModule.NetCore.SC_NotifyStartStoryDialog(triggerServicePlayer.session, dialogCid, jumpCid, entityId);
            }
            else
            {
                List<ISession> sessions = new List<ISession>();
                for (int i = 0; i < players.Count; i++)
                {
                    LevelPlayer p = players[i];
                    sessions.Add(p.session);
                }
                SLevelLogicModule.NetCore.SC_NotifyStartStoryDialog_Broadcast(sessions, dialogCid, jumpCid, entityId);
            }
        }

        /// <summary>
        /// 通知改变镜头参数（纯单机执行调用）
        /// </summary>
        /// <param name="cameraCid"></param>
        public void NotifyChangeCamera(LevelPlayer player, int cameraCid)
        {
            SLevelLogicModule.NetCore.SC_NotifyChangePlayerCamera(player.session, cameraCid);
        }

        /// <summary>
        /// 通知改变当前地区的天气
        /// </summary>
        /// <param name="id"></param>
        /// <param name="type"></param>
        public void NotifyChangeWeather(int id, int type)
        {
            List<ISession> sessions = new List<ISession>();
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer player = players[i];
                sessions.Add(player.session);
            }
            SLevelLogicModule.NetCore.SC_NotifyChangeWeather_Broadcast(sessions, id, type);
        }

        public void UpdateEntityAlert(LevelEntity entity, BaseEntity target, int alertValue)
        {
            List<ISession> sessions = new List<ISession>();
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                if (p.IsInterested(entity))
                {
                    sessions.Add(p.session);
                }
            }
            SLevelLogicModule.NetCore.SC_UpdateEntityAlert_Broadcast(sessions, entity.id, target.id, alertValue);

        }

        public void NotifyLeaderHeroChanged(LevelPlayer player)
        {
            List<ISession> sessions = new List<ISession>();
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                sessions.Add(p.session);
            }
            SLevelLogicModule.NetCore.SC_NotifyLeaderHeroChanged_Broadcast(sessions, player.entity.id, (LevelHeroPOD)player.leaderHero.GeneratePOD());
        }

        public void NotifyStartItemSubmit(LevelPlayer player, int itemSubmitCid)
        {
            SLevelLogicModule.NetCore.SC_NotifyStartItemSubmit(player.session, itemSubmitCid);
        }

        /// <summary>
        /// 通知显示掉落物
        /// </summary>
        /// <param name="player"></param>
        /// <param name="entity"></param>
        /// <param name="droppedItems"></param>
        public void NotifyDrop(LevelPlayer player, LevelEntity entity, List<RawItemData> droppedItems)
        {
            List<ISession> sessions = new List<ISession>();
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                if (entity == null || p.IsInterested(entity))
                {
                    sessions.Add(p.session);
                }
            }
            List<ItemShowPOD> itemShowPODs = new();
            foreach (var item in droppedItems)
            {
                itemShowPODs.Add(new ItemShowPOD()
                {
                    cid = item.cid,
                    num = item.num,
                    tag = ItemTag.NEW
                });
            }
            SLevelLogicModule.NetCore.SC_NotifyDrop_Broadcast(sessions, entity == null ? 0 : entity.id, itemShowPODs);
        }

        public void NotifyClearHeroBuff(LevelPlayer player, long heroId)
        {
            List<ISession> sessions = new List<ISession>();
            foreach (var p in players)
            {
                sessions.Add(p.session);
            }
            SLevelLogicModule.NetCore.SC_NotifyClearHeroBuff_Broadcast(sessions, player.id, heroId);
        }

        public void NotifyTeamWipe(LevelPlayer player)
        {
            List<ISession> sessions = new List<ISession>();
            foreach (var p in players)
            {
                sessions.Add(p.session);
            }
            SLevelLogicModule.NetCore.SC_NotifyTeamWipe_Broadcast(sessions, player.id, player.leaderHero.id);
        }

        /// <summary>
        /// 通知客户端实体特效变化
        /// </summary>
        /// <param name="player"></param>
        /// <param name="entityId"></param>
        /// <param name="resId"></param>
        /// <param name="bindPoint"></param>
        public void NotifyPlayOrStopEntityEffect(LevelPlayer player, List<LevelEntity> entities, int resId, int bindPoint, bool isAdd)
        {
            if (entities.Count == 0)
            {
                return;
            }
            if (entities.Count == 1) //只有一个实体，可以广播
            {
                var entity = entities[0];
                List<ISession> sessions = new List<ISession>();
                for (int i = 0; i < players.Count; i++)
                {
                    LevelPlayer p = players[i];
                    if (p.IsInterested(entity))
                    {
                        sessions.Add(p.session);
                    }
                }
                SLevelLogicModule.NetCore.SC_NotifyPlayOrStopEntityEffect_Broadcast(sessions, entity.id, null, resId, bindPoint, isAdd);
            }
            else
            {
                foreach (var p in players) //有多个实体，由于每个玩家的aoi不同，不能广播
                {
                    if (p.GetInterestedFromList(entities, _tempSendEntities))
                    {
                        SLevelLogicModule.NetCore.SC_NotifyPlayOrStopEntityEffect(p.session,
                            0, _tempSendEntities.ConvertAll(_converterEntitiesToIds), resId, bindPoint, isAdd);
                        _tempSendEntities.Clear();
                    }
                }
            }
        }

        public void NotifyHeroesAttr(LevelPlayer player, List<LevelHero> heroes, AttrChangeReason reason)
        {
            List<ISession> sessions = new List<ISession>();
            for (int i = 0; i < players.Count; i++)
            {
                sessions.Add(players[i].session);
            }
            List<LevelHeroAttrSyncPOD> pods = new();
            foreach (var hero in heroes)
            {
                pods.Add(new LevelHeroAttrSyncPOD()
                {
                    id = hero.id,
                    hp = hero.hp,
                    sp = hero.sp
                });
            }
            SLevelLogicModule.NetCore.SC_NotifyHeroesAttr_Broadcast(sessions, player.id, pods, reason);
        }

        public void NotifyRevive(LevelPlayer player)
        {
            List<ISession> sessions = new List<ISession>();
            for (int i = 0; i < players.Count; i++)
            {
                sessions.Add(players[i].session);
            }
            SLevelLogicModule.NetCore.SC_NotifyRevive_Broadcast(sessions, player.id);
        }

        public void NotifyPushEntity(LevelPlayer player, LevelEntity entity, int maxDistance)
        {
            SLevelLogicModule.NetCore.SC_NotifyPushEntity(player.session, entity.id, maxDistance);
        }

        public void NotifyStartMiniGame(LevelPlayer player, LevelMiniGameType type, int cid)
        {
            SLevelLogicModule.NetCore.SC_NotifyStartMiniGame(player.session, type, cid);
        }

        public void NotifyChangeEntityAudio(LevelPlayer player, LevelEntity entity, int audioCid)
        {
            List<ISession> sessions = new List<ISession>();
            for (int i = 0; i < players.Count; i++)
            {
                LevelPlayer p = players[i];
                if (p.IsInterested(entity))
                {
                    sessions.Add(p.session);
                }
            }
            SLevelLogicModule.NetCore.SC_NotifyChangeEntityAudio_Broadcast(sessions, entity.id, audioCid);
        }
        #endregion
    }
}
